/*
 * Copyright (C) 2005, Velocityme Partnership
 * LicenseGenerator.java
 *
 * Created on 13 June 2005, 06:59
 */

package com.velocityme.licence;

import com.velocityme.utility.LicenceKey;
import com.velocityme.utility.LicenceKeyFloating;
import com.velocityme.utility.LicenceKeySingleUsername;
import com.velocityme.utility.SignedLicenceKey;
import java.beans.XMLEncoder;
import java.io.*;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Calendar;
import java.util.Date;
import java.util.zip.Deflater;
import javax.crypto.*;
import sun.misc.BASE64Encoder;

/**
 *
 * @author  Robert
 */
public class LicenceGenerator {
    
    private PrivateKey m_signingKey;
    private PublicKey m_encryptingKey;
    
    /** Creates a new instance of LicenseGenerator */
    public LicenceGenerator() {
        InputStream is = getClass().getResourceAsStream("/com/velocityme/licence/licenceSigning.key");
        if (is != null) {
            try {
                byte[] encKey = new byte[is.available()];
                is.read(encKey);
                is.close();
                PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encKey);
                KeyFactory keyFactory = KeyFactory.getInstance("DSA");
                m_signingKey = keyFactory.generatePrivate(privateKeySpec);
                System.out.println("Successfully loaded signing key!");
            } catch(IOException e) {
                System.out.println(e.getMessage());
            } catch(NoSuchAlgorithmException e) {
                System.out.println(e.getMessage());
            } catch(InvalidKeySpecException e) {
                System.out.println(e.getMessage());
            }
        }
        else {
            try {
                // Generate a 1024-bit Digital Signature Algorithm (DSA) key pair
                KeyPairGenerator serverGen = KeyPairGenerator.getInstance("DSA");
                serverGen.initialize(1024);
                KeyPair serverPair = serverGen.genKeyPair();
                X509EncodedKeySpec ksp = new X509EncodedKeySpec(serverPair.getPublic().getEncoded());
                FileOutputStream fos = new FileOutputStream("licenceVerification.key");
                fos.write(ksp.getEncoded());
                fos.close(); 
                PKCS8EncodedKeySpec ksp2 = new PKCS8EncodedKeySpec(serverPair.getPrivate().getEncoded());
                fos = new FileOutputStream("licenceSigning.key");
                fos.write(ksp2.getEncoded());
                fos.close(); 

                KeyPairGenerator clientGen = KeyPairGenerator.getInstance("RSA");
                clientGen.initialize(1024);
                KeyPair clientPair = clientGen.genKeyPair();
                m_signingKey = serverPair.getPrivate();
                m_encryptingKey = clientPair.getPublic();
            } catch(NoSuchAlgorithmException e1) {
            } catch(FileNotFoundException e1) {
            } catch(IOException e1) {
            }
        }
    }
    
    private String signedLicenceKey(LicenceKey p_licenceKey) {
        try {
            Signature sig = Signature.getInstance(m_signingKey.getAlgorithm());
            SignedLicenceKey signedLicenceKey = new SignedLicenceKey(p_licenceKey, m_signingKey, sig);
        
            // Step 3: now encrypt it so that only the destination organisation can use it!
            ByteArrayOutputStream bos = new ByteArrayOutputStream() ;
            XMLEncoder out = new XMLEncoder(bos);
            out.writeObject(signedLicenceKey);
            out.close();
            byte[] enc = bos.toByteArray();
           
            // now compress the byte array
            Deflater compressor = new Deflater();
            compressor.setLevel(Deflater.BEST_COMPRESSION);
            compressor.setInput(enc);
            compressor.finish();
            ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            while (!compressor.finished()) {
                int count = compressor.deflate(buf);
                bos2.write(buf, 0, count);
            }
            try {
                bos2.close();
            } catch (IOException e) {
            }
            byte[] compressedData = bos2.toByteArray();

            // Step 4: finally convert it to a base64 string
            return new BASE64Encoder().encode(compressedData);
        } catch (IOException e) {
            System.err.println(e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            System.err.println(e.getMessage());
        } catch (InvalidKeyException e) {
            System.err.println(e.getMessage());
        } catch (SignatureException e) {
            System.err.println(e.getMessage());
//        } catch (NoSuchPaddingException e) {
//            System.err.println(e.getMessage());
//        } catch (IllegalBlockSizeException e) {
//            System.err.println(e.getMessage());
//        } catch (BadPaddingException e) {
//            System.err.println(e.getMessage());
        }
        return "";        
    }
    
    public String generateLicenceKeySingleUsername(Date p_expiryDate, String p_clientGUID, String p_username) {
        LicenceKey licenceKey = new LicenceKeySingleUsername(p_expiryDate, p_clientGUID, p_username);
        return signedLicenceKey(licenceKey);
    }
    
    public String generateLicenceKeyFloating(Date p_expiryDate, String p_clientGUID, int p_number) {
        LicenceKey licenceKey = new LicenceKeyFloating(p_expiryDate, p_clientGUID, p_number);
        return signedLicenceKey(licenceKey);
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        LicenceGenerator licenceGenerator = new LicenceGenerator();
        int numberOfMonths = 0;
        System.out.println("Usage: LicenceGenerator numMonths clientGUID username");
        System.out.println("   or: LicenceGenerator numMonths clientGUID numFloat");
        try {
            numberOfMonths = Integer.parseInt(args[0]);
        } catch(NumberFormatException e) {
            System.out.println("Couldn't parse number of months!");
            return;
        }
        Calendar expiryDate = Calendar.getInstance();
        expiryDate.add(Calendar.MONTH, numberOfMonths);
        String clientGUID = args[1];
        if (clientGUID.length() != 32) {
            System.out.println("Invalid client GUID!");
            return;
        }
        try {
            int numFloat = Integer.parseInt(args[2]);
            System.out.println(licenceGenerator.generateLicenceKeyFloating(expiryDate.getTime(), clientGUID, numFloat));
        } catch(NumberFormatException e) {
            System.out.println(licenceGenerator.generateLicenceKeySingleUsername(expiryDate.getTime(), clientGUID, args[2]));
        }
    }
    
}
